﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Reflection;
using Spac.Contract;
using Spac.Launcher.Properties;

namespace Spac.Launcher
{
    class Program
    {
        static void Main(string[] args)
        {
            ISpac spac = AssemblyLoader.CreateChannel();

            List<ApplicationInfo> apps = spac.GetApplications();

            Console.WriteLine("SPAC Applicatios:");
            for (int i = 0; i < apps.Count;i++)
            {
                ApplicationInfo a = apps[i];
                Console.Write(i.ToString() + " : ");
                Console.WriteLine(a.ApplicationName);
            }

            Console.WriteLine("Choose Application or enter 'exit'...");
            string input = Console.ReadLine();
            if (input == "exit")
                return;

            ApplicationInfo exe = apps[int.Parse(input)];

            AppDomainSetup appSetup = new AppDomainSetup();
            appSetup.ConfigurationFile = exe.ConfigurationUrl;

            AppDomain app = AppDomain.CreateDomain("SpacMainDomain", AppDomain.CurrentDomain.Evidence, appSetup);
            app.AssemblyResolve += new ResolveEventHandler(ResovleAssembly);

            app.ExecuteAssemblyByName(exe.AssemblyFullName);
        }

        static Assembly ResovleAssembly(object sender, ResolveEventArgs args)
        {
            //SpacMainDomain
            AppDomain currentDomain = sender as AppDomain;

            //this domain is needed, because you have to access the SpacLauncher's Config to load the WCF Client Endpoint
            AppDomain spacLoaderDomain = AppDomain.CreateDomain("SpacLoaderDomain");

            //create AssemblyLoader in the SpacLoaderDomain
            AssemblyLoader assemblyLoader = (AssemblyLoader)spacLoaderDomain.CreateInstanceAndUnwrap(
                Assembly.GetExecutingAssembly().FullName,
                    "Spac.Launcher.AssemblyLoader");

            //execute the AssemblyLoader int the SpacLoaderDomain
            byte[] bin = assemblyLoader.LoadAssembly(args.Name);

            //load Assembly into the SpacMainDomain
            Assembly assembly = currentDomain.Load(bin);

            return assembly;
        }

    }

    public class AssemblyLoader : MarshalByRefObject
    {
        public byte[] LoadAssembly(string name)
        {
            try
            {
                ISpac spac = CreateChannel();
                byte[] binary = spac.GetAssembly(name);

                return binary;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        internal static ISpac CreateChannel()
        {
            ChannelFactory<ISpac> channelFactory = new ChannelFactory<ISpac>("Spac");
            return channelFactory.CreateChannel();
        }
    }
}
